package com.beerandjesus.sportofkings.handicapper.strategy.brisnet.singlefile;

import java.math.BigDecimal;
import java.util.List;

import org.apache.commons.lang.StringUtils;

import com.beerandjesus.sportofkings.handicapper.model.*;
import com.beerandjesus.sportofkings.handicapper.model.brisnet.singlefile.Horse;
import com.beerandjesus.sportofkings.handicapper.model.brisnet.singlefile.HorseRace;
import com.beerandjesus.sportofkings.handicapper.model.brisnet.singlefile.PastPerformance;
import com.beerandjesus.sportofkings.handicapper.model.brisnet.singlefile.Race;

public class NonMaidenRaceAnalysisStrategyImpl extends
		AbstractRaceAnalysisStrategy implements
		NonMaidenRaceAnalysisStrategy<HorseRace> {
	
	private static final int MAX_RACES_FOR_WPS_CONSIDERATION = 5;

	private static final int MAX_RACES_FOR_SPEED_CONSIDERATION = 6;

	private static final int MAX_RACES_FOR_UP_CLOSE_CONSIDERATION = 8;

	private static final String[] TABLE_HEADERS = new String[] {
		Q_PTS, UP_CLOSE, W_OFF_PACE, SPEED, WPS, WORKS, NAME, MORNING_LINE
	};
	
	private static final BigDecimal TWO_AND_THREE_QUARTERS = new BigDecimal("2.75");
	private static final BigDecimal THREE_AND_A_HALF = new BigDecimal("3.5");

    public RaceAnalysisResultVO analyze(HorseRace race) {
		Race r = race.getRace();
		List<Horse> horses = race.getHorses();
		RaceAnalysisResultVOImpl vo = new RaceAnalysisResultVOImpl();
		setCommonFields(vo, r, horses);
		ResultsTableImpl table = new ResultsTableImpl(TABLE_HEADERS);
		for (Horse h : horses) {
			Integer pp = new Integer(h.getPostPosition());
			Integer qPts;
			try {
				qPts = new Integer(h.getQuirinSpeedPoints());
			} catch (NumberFormatException e) {
				qPts = -1;
			}
			ResultType type;
			if (qPts < 0) {
				type = ResultType.UNKNOWN;
			} else if (qPts < 4) {
				type = ResultType.SLOW_EARLY_SPEED;
			} else {
				type = ResultType.FAST_EARLY_SPEED;
			}
			// name
			table.putValue(pp, type, NAME, h.getName());
			// Quirin style speed points
			table.putValue(pp, type, Q_PTS, qPts.toString());
			switch (type) {
			case SLOW_EARLY_SPEED:
				// Up close 2 times within last 8 races
				// up close =
				// 2 3/4 lengths at 2nd call for sprints
				// 3 1/2 lengths at 2nd call for routes
				int upCloseCount = 0;
				int raceCount = 0;
				for (PastPerformance perf : h.getPastPerformances()) {
					raceCount++;
					if (raceCount > MAX_RACES_FOR_UP_CLOSE_CONSIDERATION) {
						break;
					}
					String lenOrMarg = perf.getCall2ndLenOrMargin();
					if (!StringUtils.isEmpty(lenOrMarg)) {
						BigDecimal lom = new BigDecimal(lenOrMarg);
						BigDecimal comp;
						if (calc.isRoute(perf.getDistance())) {
							comp = THREE_AND_A_HALF;
						} else {
							comp = TWO_AND_THREE_QUARTERS;
						}
						if (lom.compareTo(comp) <= 0) {
							upCloseCount++;
						}
					}
				}
				String upClose = "no";
				if (upCloseCount > 1) {
					upClose = "yes";
				}
				table.putValue(pp, type, UP_CLOSE, upClose);
				table.putValue(pp, type, W_OFF_PACE, "");
				break;
            case FAST_EARLY_SPEED:
                // Note if runner can win off pace.
                // Any occurrence in past performances passes.
                String winsOffPace = "no";
                for (PastPerformance perf : h.getPastPerformances()) {
                    if (equal(perf.getFinishPosition(), 1) && greaterThan(perf.getCallPositionSecond(), 1)) {
                        winsOffPace = "yes";
                        break;
                    }
                }
                table.putValue(pp, type, W_OFF_PACE, winsOffPace);
                table.putValue(pp, type, UP_CLOSE, "");

                break;
			}
			// Speed & wps
			Integer par = getInteger(r.getBrisSpeedPar(), 0);
			int raceCount = 0;
			int maxSpeed = 0;
			int parCount = 0;
			int[] wps = new int[3];
			for (PastPerformance perf : h.getPastPerformances()) {
				raceCount++;
				if (raceCount <= MAX_RACES_FOR_SPEED_CONSIDERATION) {
					Integer speed = getInteger(perf.getBrisSpeedRating(), 0);
					if (speed > maxSpeed) {
						maxSpeed = speed;
					}
					if (speed >= par) {
						parCount++;
					}
				}
				if (raceCount <= MAX_RACES_FOR_WPS_CONSIDERATION) {
					Integer pos = getInteger(perf.getFinishPosition(), 99);
					if (pos == 1) {
						wps[0]++;
					} else if (pos == 2) {
						wps[1]++;
					} else if (pos == 3) {
						wps[2]++;
					}
				}

			}
			table.putValue(pp, type, SPEED, parCount + "par " + maxSpeed);
			table.putValue(pp, type, WPS, wps[0] + " " + wps[1] + " " + wps[2]);
			StringBuffer works = new StringBuffer("");
			// Workouts
			getSharpWorkouts(h, works);
			table.putValue(pp, type, WORKS, works.toString());
            morningLineOdds(h, table, pp, type);

		}

		vo.setResultsTable(table);
		return vo;
	}

}
